﻿using Quartz;
using Quartz.Impl.Matchers;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace ZYing.QPanel
{
    public class XmlTriggerStorePlugin : ISchedulerPlugin, ISchedulerListener
    {
        public string Name { get; private set; }

        public IScheduler Scheduler { get; private set; }
        public Task Initialize(string pluginName, IScheduler scheduler, CancellationToken cancellationToken = default)
        {
            Name = pluginName;
            Scheduler = scheduler;
            scheduler.ListenerManager.AddSchedulerListener(this);
            return Task.CompletedTask;
        }

        [Serializable]
        public class Store
        {
            public List<TriggerKey> TriggerKeys { get; set; } = new List<TriggerKey>();
            private static Object SyncRoot = new object();
            public void Save()
            {
                var fn = GetSavePath();
                lock (SyncRoot)
                {
                    var xs = new System.Xml.Serialization.XmlSerializer(typeof(Store));
                    using (var fs = new FileStream(fn, FileMode.Create))
                    {
                        xs.Serialize(fs, this);
                    }
                }
            }
            public static Store Read()
            {
                var fn = GetSavePath();

                lock (SyncRoot)
                {
                    if (!File.Exists(fn)) return new Store();
                    var xs = new System.Xml.Serialization.XmlSerializer(typeof(Store));
                    try
                    {
                        using (var fs = File.OpenRead(fn))
                        {
                            return (Store)xs.Deserialize(fs);
                        }
                    }
                    catch
                    {
                        return new Store();
                    }
                }
            }
            private static string GetSavePath()
            {
                var fn = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config");
                if (!Directory.Exists(fn)) Directory.CreateDirectory(fn);
                fn = Path.Combine(fn, "XmlTriggerStorePlugin.Store.xml");
                return fn;
            }
        }
        private async Task Save(bool force = false)
        {
            if (!this.Scheduler.IsStarted && !force) return;
            var keys = await this.Scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup());
            var store = new Store();
            foreach (var key in keys)
            {
                var state = await this.Scheduler.GetTriggerState(key);
                if (state == TriggerState.Paused) continue;
                store.TriggerKeys.Add(key);
            }
            store.Save();
        }

        public Task Start(CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public Task Shutdown(CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public Task JobScheduled(ITrigger trigger, CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public Task JobUnscheduled(TriggerKey triggerKey, CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public Task TriggerFinalized(ITrigger trigger, CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public async Task TriggerPaused(TriggerKey triggerKey, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task TriggersPaused(string triggerGroup, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task TriggerResumed(TriggerKey triggerKey, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task TriggersResumed(string triggerGroup, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task JobAdded(IJobDetail jobDetail, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task JobDeleted(JobKey jobKey, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task JobPaused(JobKey jobKey, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public Task JobInterrupted(JobKey jobKey, CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public async Task JobsPaused(string jobGroup, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task JobResumed(JobKey jobKey, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public async Task JobsResumed(string jobGroup, CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public Task SchedulerError(string msg, SchedulerException cause, CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public Task SchedulerInStandbyMode(CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public Task SchedulerStarted(CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public async Task SchedulerStarting(CancellationToken cancellationToken = default)
        {
            //只启动启用状态的触发器
            var keys = await Scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup(), cancellationToken);
            var store = Store.Read();
            var set = new HashSet<TriggerKey>(store.TriggerKeys);
            foreach (var key in keys)
            {
                if (!set.Contains(key)) await Scheduler.PauseTrigger(key, cancellationToken);
            }
        }

        public Task SchedulerShutdown(CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }

        public async Task SchedulerShuttingdown(CancellationToken cancellationToken = default)
        {
            await Save();
        }

        public Task SchedulingDataCleared(CancellationToken cancellationToken = default)
        {
            return Task.CompletedTask;
        }
    }
}
